﻿using gt.rediscachemanager.Configuration;
using gt.rediscachemanager.Entry;
using gt.rediscachemanager.Utility;
using StackExchange.Redis;
using System;
using System.Threading.Tasks;

namespace gt.rediscachemanager.Impl.RedisClient
{
    public partial class RedisClient : IRedisClient
    {
        public long StringBitCount(string key, long start = 0, long end = -1, StackExchange.Redis.CommandFlags flags = CommandFlags.None)
        {
            var message = new StringBitCountMessage(key, start, end);
            return Execute(RedisCommand.StringBitCount, message, flags);
        }

        public long StringBitOperation(StackExchange.Redis.Bitwise operation, string destination, string[] keys, StackExchange.Redis.CommandFlags flags = CommandFlags.None)
        {
            if (this.Pool.Mode != PoolMode.Single)
                throw new InvalidOperationException("this operation do not support by cluster mode!");
            var redisKeys = RedisValueUtility.ConvertToRedisKeyFromString(keys);
            var message = new StringBitOperationArrayMessage(destination, operation, redisKeys);
            return Execute(RedisCommand.StringBitOperationArray, message, flags);
        }

        public long StringBitOperation(StackExchange.Redis.Bitwise operation, string destination, string first, string second = null, StackExchange.Redis.CommandFlags flags = CommandFlags.None)
        {
            if (this.Pool.Mode != PoolMode.Single)
                throw new InvalidOperationException("this operation do not support by cluster mode!");
            var message = new StringBitOperationMessage(destination, operation, first, second);
            return Execute(RedisCommand.StringBitOperation, message, flags);
        }

        public long StringBitPosition(string key, bool bit, long start = 0, long end = -1, StackExchange.Redis.CommandFlags flags = CommandFlags.None)
        {
            var message = new StringBitPositionMessage(key, bit, start, end);
            return Execute(RedisCommand.StringBitPosition, message, flags);
        }

        public bool StringGetBit(string key, long offset, StackExchange.Redis.CommandFlags flags = CommandFlags.None)
        {
            var message = new StringGetBitMessage(key, offset);
            return Execute(RedisCommand.StringGetBit, message, flags);
        }

        public bool StringSetBit(string key, long offset, bool bit, StackExchange.Redis.CommandFlags flags = CommandFlags.None)
        {
            var message = new StringSetBitMessage(key, bit, offset);
            return Execute(RedisCommand.StringSetBit, message, flags);
        }

        #region Async

        public async Task<long> StringBitCountAsync(string key, long start = 0, long end = -1, StackExchange.Redis.CommandFlags flags = CommandFlags.None)
        {
            var message = new StringBitCountMessage(key, start, end);
            return await ExecuteAsync(RedisCommand.StringBitCount, message, flags).ConfigureAwait(false);
        }

        public async Task<long> StringBitOperationAsync(StackExchange.Redis.Bitwise operation, string destination, string[] keys, StackExchange.Redis.CommandFlags flags = CommandFlags.None)
        {
            if (this.Pool.Mode != PoolMode.Single)
                throw new InvalidOperationException("this operation do not support by cluster mode!");
            var redisKeys = RedisValueUtility.ConvertToRedisKeyFromString(keys);
            var message = new StringBitOperationArrayMessage(destination, operation, redisKeys);
            return await ExecuteAsync(RedisCommand.StringBitOperationArray, message, flags).ConfigureAwait(false);
        }

        public async Task<long> StringBitOperationAsync(StackExchange.Redis.Bitwise operation, string destination, string first, string second = null, StackExchange.Redis.CommandFlags flags = CommandFlags.None)
        {
            if (this.Pool.Mode != PoolMode.Single)
                throw new InvalidOperationException("this operation do not support by cluster mode!");
            var message = new StringBitOperationMessage(destination, operation, first, second);
            return await ExecuteAsync(RedisCommand.StringBitOperation, message, flags).ConfigureAwait(false);
        }

        public async Task<long> StringBitPositionAsync(string key, bool bit, long start = 0, long end = -1, StackExchange.Redis.CommandFlags flags = CommandFlags.None)
        {
            var message = new StringBitPositionMessage(key, bit, start, end);
            return await ExecuteAsync(RedisCommand.StringBitPosition, message, flags).ConfigureAwait(false);
        }

        public async Task<bool> StringGetBitAsync(string key, long offset, StackExchange.Redis.CommandFlags flags = CommandFlags.None)
        {
            var message = new StringGetBitMessage(key, offset);
            return await ExecuteAsync(RedisCommand.StringGetBit, message, flags).ConfigureAwait(false);
        }

        public async Task<bool> StringSetBitAsync(string key, long offset, bool bit, StackExchange.Redis.CommandFlags flags = CommandFlags.None)
        {
            var message = new StringSetBitMessage(key, bit, offset);
            return await ExecuteAsync(RedisCommand.StringSetBit, message, flags).ConfigureAwait(false);
        }

        #endregion
    }
}
